package com.xrkol.sharelib.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;

import me.donnior.rtl.paginate.PaginateSupportArray;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.xrkol.sharelib.constants.BaseConstants;
import com.xrkol.sharelib.dao.BaseDao;
import com.google.common.base.Strings;

/**
 * 数据持久层基类
 * 
 * @param <T>
 * @param <I>
 */
@Transactional
public abstract class BaseDaoImpl<T, I extends Serializable> implements BaseDao<T, I> {

    static final int DEFAULT_PAGESIZE = 10;

    @PersistenceContext
    private EntityManager entityManager;

    private Class<T> entityClass;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }

    @Override
    public void save(T entity) {
        entityManager.persist(entity);
    }

    @Override
    public void update(T entity) {
        entityManager.merge(entity);
    }

    @Override
    public void delete(I id) {
        final Class<T> pclass = this.entityClass;
        T t = entityManager.find(pclass, id);
        if (null != t) {
            entityManager.remove(t);
        }
    }

    @Override
    public T findById(I id) {
        if (id == null) {
            return null;
        }
        final Class<T> pclass = this.entityClass;
        return entityManager.find(pclass, id);
    }

    public int executeCountQuery(String queryString, Object... restricts) {
        Query query = entityManager.createQuery(queryString);
        for (int i = 0; i < restricts.length; i++) {
            query.setParameter(i + 1, restricts[i]);
        }
        Number singleResult = null;
        try {
            singleResult = (Number) query.getSingleResult();
        } catch (NoResultException e) {
        }
        return null == singleResult ? 0 : singleResult.intValue();
    }

    public int executeQuery(String queryString, Object... restricts) {
        Query query = entityManager.createQuery(queryString);
        for (int i = 0; i < restricts.length; i++) {
            query.setParameter(i + 1, restricts[i]);
        }
        Object[] results = null;
        try {
            results = (Object[]) query.getResultList().get(0);
        } catch (NoResultException e) {
        }
        Number total = (Number) results[0];
        return null == total ? 0 : total.intValue();
    }

    /**
     * 分页查询
     * 
     * @param queryString
     *            查询语句
     * @param order
     *            排序
     * @param page
     *            页面序号
     * @param restricts
     *            参数集合
     * @return
     */
    @SuppressWarnings("unchecked")
    protected PaginateSupportArray<T> executeQueryWithPagination(String queryString, String order,
            Integer page, Object... restricts) {
        if (page == null || page < 0) {
            page = 1;
        }
        int total = executeCountQuery("select count(*) " + queryString, restricts);

        String queryWithOrd = Strings.isNullOrEmpty(order) ? queryString : (queryString + order);
        Query query = entityManager.createQuery(queryWithOrd);
        setParameter(query, restricts);
        query.setFirstResult((page - 1) * DEFAULT_PAGESIZE);
        query.setMaxResults(DEFAULT_PAGESIZE);

        List<T> result = query.getResultList();
        PaginateSupportArray<T> paginateList = new PaginateSupportArray<T>(result);
        paginateList.setPage(page);
        paginateList.setTotal(total);
        paginateList.setPageSize(DEFAULT_PAGESIZE);

        return paginateList;
    }

    @SuppressWarnings("unchecked")
    protected PaginateSupportArray<T> executeQueryWithPaginationWithoutTotal(String queryString,
            String order, Integer page, Object... restricts) {
        if (page == null || page < 0) {
            page = 1;
        }

        String queryWithOrd = Strings.isNullOrEmpty(order) ? queryString : (queryString + order);
        Query query = entityManager.createQuery(queryWithOrd);
        setParameter(query, restricts);
        query.setFirstResult((page - 1) * DEFAULT_PAGESIZE);
        query.setMaxResults(DEFAULT_PAGESIZE);

        List<T> result = query.getResultList();
        PaginateSupportArray<T> paginateList = new PaginateSupportArray<T>(result);
        paginateList.setPage(page);
        paginateList.setPageSize(DEFAULT_PAGESIZE);

        return paginateList;
    }

    /**
     * 分页查询(需传递PageSize)
     * 
     * @param queryString
     *            查询语句
     * @param pageSize
     *            自己定义每页显示个数
     * @param order
     *            排序
     * @param page
     *            页面序号
     * @param restricts
     *            参数集合
     * @return
     */
    @SuppressWarnings("unchecked")
    protected PaginateSupportArray<T> executeQueryWithPaginationWithPageSize(String queryString,
            Integer pageSize, String order, Integer page, Object... restricts) {
        if (page == null || page < 0) {
            page = 1;
        }
        int total = executeCountQuery("select count(*) " + queryString, restricts);

        String queryWithOrd = Strings.isNullOrEmpty(order) ? queryString : (queryString + order);
        Query query = entityManager.createQuery(queryWithOrd);
        setParameter(query, restricts);
        query.setFirstResult((page - 1) * pageSize);
        query.setMaxResults(pageSize);

        List<T> result = query.getResultList();
        PaginateSupportArray<T> paginateList = new PaginateSupportArray<T>(result);
        paginateList.setPage(page);
        paginateList.setTotal(total);
        paginateList.setPageSize(pageSize);

        return paginateList;
    }

    /**
     * 不带分页的查询
     * 
     * @param queryString
     *            查询语句
     * @param restricts
     *            参数集合
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<T> executeQueryWithoutPaging(String queryString, Object... restricts) {
        Query query = entityManager.createQuery(queryString);
        for (int i = 0; i < restricts.length; i++) {
            query.setParameter(i + 1, restricts[i]);
        }
        return query.getResultList();
    }

    /**
     * 执行操作删除
     * 
     * @param sqlString
     *            操作语句
     * @param restricts
     *            参数集合
     * @return
     */
    protected int executeUpdateOrDelete(String sqlString, Object... restricts) {
        Query query = entityManager.createQuery(sqlString);
        setParameter(query, restricts);
        return query.executeUpdate();

    }

    /**
     * 返回单一结果的查询语句(INT)
     * 
     * @param sqlString
     * @return
     */
    protected int executeSingleResult(String sqlString) {
        Query query = entityManager.createQuery(sqlString);
        Number singleResult = null;
        try {
            singleResult = (Number) query.getSingleResult();
        } catch (NoResultException e) {
        }
        return null == singleResult ? 0 : singleResult.intValue();
    }

    /**
     * 将参数集合逐项设置到Query对象中
     * 
     * @param query
     * @param restricts
     */
    protected void setParameter(Query query, Object... restricts) {
        for (int i = 0; i < restricts.length; i++) {
            query.setParameter(i + 1, restricts[i]);
        }
    }

    /**
     * Clear
     */
    public void flush() {
        entityManager.flush();
        entityManager.clear();
    }

    public String getCurrentSchoolId() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        String schoolId = (String) request.getSession().getAttribute(BaseConstants.WEB_SCHOOL_ID);
        return schoolId;
    }

}
